import React, {
  useContext,
  useState,
  useEffect,
  useRef,
  useImperativeHandle,
  useCallback,
} from 'react';
import { Form } from 'antd';
import EditableContext from './editableContext';
import FormItemType from './FormItemType';
import type { IFormItemType } from './FormItemType';
import type { RuleObject } from 'antd/lib/form/index';
interface Item {
  key: string;
}

type editData = IFormItemType & {
  afterEdit?: (value: string, record: any) => undefined | object;
  beforEdit?: (record: any) => boolean | object;
  onChange?: (value: string, record: object, dataIndex: string) => void;
  rules?: RuleObject[];
};
interface EditableCellProps {
  title: React.ReactNode;
  editData?: editData;
  children: React.ReactNode;
  dataIndex: keyof Item;
  record: Item;
  rowIndex: number;
  handleSave: (record: Item) => void;
}

const EditableCell: React.FC<EditableCellProps> = ({
  title,
  editData,
  children,
  dataIndex,
  record,
  handleSave,
  rowIndex,
  ...restProps
}) => {
  const [editing, setEditing] = useState(false);
  const inputRef = useRef<any>(null);
  const { form, refs } = useContext(EditableContext)!;
  const ref = useRef<any>();

  const isValid = useRef(false);
  const handleChange = useCallback((value) => {
    isValid.current = false;
    editData?.onChange?.(value, record, dataIndex);
  }, []);

  useEffect(() => {
    if (refs && editData && editData.rules) {
      refs[dataIndex] = ref;
    }
  }, []);

  useImperativeHandle(
    ref,
    () => ({
      startEdit: () => {
        form.setFieldsValue({ [dataIndex]: record[dataIndex] });
        setEditing(true);
        isValid.current = true;
      },
      endEdit: () => {
        setEditing(false);
      },
      focus: () => {
        inputRef.current?.focus?.();
      },
    }),
    [record],
  );

  useEffect(() => {
    if (editing && !isValid.current) {
      inputRef.current?.focus?.();
    }
  }, [editing]);

  const toggleEdit = () => {
    setEditing(!editing);
    form.setFieldsValue({ [dataIndex]: record[dataIndex] });
  };

  const save = async () => {
    if (isValid.current) {
      isValid.current = false;
      return;
    }
    try {
      const values = await form.validateFields();
      toggleEdit();
      const newRecord = { ...record, ...values };
      handleSave(editData?.afterEdit?.(values[dataIndex], newRecord) || newRecord);
    } catch (errInfo) {
      console.log('Save failed:', errInfo);
    }
  };

  let childNode = children;

  if (editData) {
    const { rules, afterEdit, beforEdit, ...edit } = editData;
    let showEdit = true,
      newEdit = { ...edit };
    if (beforEdit) {
      const result = beforEdit?.(record);
      if (typeof result === 'boolean') {
        showEdit = result;
      } else {
        Object.assign(newEdit, result);
      }
    }

    const isEnter = edit.type.includes('Input') || edit.type === 'TextArea';
    const isIconPicker = edit.type === 'IconPicker';
    childNode =
      showEdit && editing ? (
        <Form.Item style={{ margin: 0 }} name={dataIndex} rules={rules}>
          {isEnter ? (
            <FormItemType
              {...newEdit}
              ref={inputRef}
              onBlur={save}
              onPressEnter={save}
              pVisible={true}
              rowIndex={rowIndex}
              onChange={handleChange}
            />
          ) : isIconPicker ? (
            <FormItemType
              {...newEdit}
              ref={inputRef}
              rowIndex={rowIndex}
              pVisible={true}
              onChange={(value) => {
                handleChange(value);
                return save();
              }}
            />
          ) : (
            <FormItemType
              {...newEdit}
              ref={inputRef}
              rowIndex={rowIndex}
              onBlur={save}
              onChange={handleChange}
            />
          )}
        </Form.Item>
      ) : (
        <div className="editable-cell-value-wrap" onClick={showEdit ? toggleEdit : undefined}>
          {children}
        </div>
      );
  }

  return <td {...restProps}>{childNode}</td>;
};

export default EditableCell;
export type { editData };
